#include <unistd.h>
#include <QString>
#include <QDebug>
#include <QObject>
#include <QHttp>
#include <QAbstractSocket>
#include <QFileInfo>
#include <QHttp>
#include <QUrl>
#include <QtGui>
#include <QTimer>
#include <QDomDocument>
#include <QDomProcessingInstruction>
#include <QApplication>
#include <QNetworkInterface>
#include <QHostAddress>
#include <QtGui>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <QObject>

#if defined Q_WS_MAC
#define WEBAGENTNAME "Mac QT4 / PPK_W @ciz.ch"
#endif
#if defined Q_WS_WIN
#define WEBAGENTNAME "Windows QT4 / PPK_W @ciz.ch"
#endif
#if defined Q_WS_X11
#define WEBAGENTNAME "Unix QT4 / PPK_W @ciz.ch"
#endif



#define WORKMAIN 5

/* write a file to utf-8 format */
static inline bool fwriteutf8(QString fullFileName,QString xml)
{
    if (fullFileName.contains("/", Qt::CaseInsensitive)) {
    QString ultimacartellaaperta = fullFileName.left(fullFileName.lastIndexOf("/"))+"/";
    QDir dira(ultimacartellaaperta);
    if ( dira.mkpath(ultimacartellaaperta) ) { } else {
    return false;
    }
    }
    
        QTextCodec *codecx;
        codecx = QTextCodec::codecForMib(106);
        QFile f( fullFileName );
        if ( f.open( QFile::WriteOnly | QFile::Text ) )
        {
        QTextStream sw( &f );
        sw.setCodec(codecx);
        sw << xml;
        f.close();
        return true;
        }
        return false;
}

static inline QString UserLanguage()
{
     QString languser,languagesistem,langqt; 
	QLocale loci = QLocale::system();
             languser = getenv("LANG");
             languser = languser.toLower();
             languagesistem = loci.name();
             languagesistem = languagesistem.toLower();
	     languagesistem = languagesistem.left(2);
     /* Window XP Prof MUI Multiuser == stay only "c" language && user setting setenv !!! */
     if (languagesistem == "c") { 
         if (languser.size() > 2 && languser.contains("_")) {
             languagesistem = languser.left(2);
         }
     }
     return languagesistem;
}
static inline bool is_file(QString fullFileName)
{
    if (!fullFileName.size() > 3) {
      return false;  
    }
    QFile f( fullFileName );
	if ( f.exists(fullFileName) ) {
    return true;  
	} else {
	return false;
    }
}

static inline bool NetworkEnable() {

    bool validip = false;
    QList<QHostAddress> addrlist = QNetworkInterface::allAddresses();
    int o = -1;
    foreach(QHostAddress addr, addrlist){
    o++;
    QNetworkInterface hop = QNetworkInterface::interfaceFromIndex(o);
    QString mach = hop.hardwareAddress(); 
    QString name = hop.name();
    QString oneip = addr.toString();
        if (!oneip.contains("127.")) {
         bool actual = hop.isValid();
            if (actual) {
             validip = true;  
            }
        }
    }
return validip;
}

static inline QString UriConvert( QString touri )
{
    touri = touri.toLower();
    QStringList piece = touri.split("");
    QString alloweduri = "abcdefghijklmnopqrstuvwxyz1234567890";
    QStringList alist = alloweduri.split("");
    
     for (int i = 0; i < piece.size(); ++i) {
           QString pin = piece.at(i);
           if (!alist.contains(pin)) {
               touri.replace(pin,"");
           }
       }
    
    return touri;
}

/* ############################# class starts ################################################*/



class HTTP_option : public QHttp
{
    Q_OBJECT

public: HTTP_option( QUrl urigo , QObject * parent = 0 )
{
 urigoup = QUrl(urigo);
 davoption ="";
 davlevel = "";
 allowlist.clear();
 setHost(urigoup.host(), 80);
 setUser(urigoup.userName(),urigoup.password());
 header.setRequest("OPTIONS",urigoup.path(),1,1);
 header.setValue("Host",urigoup.host());
 header.setValue("User-Agent", WEBAGENTNAME );
 header.setValue("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
 header.setValue("Accept-Language", "it,de-de;q=0.8,it-it;q=0.6,en-us;q=0.4,en;q=0.2");
 header.setValue("Connection", "keep-alive");
}
void Start()
{
  david = request(header,0,0);
  std::cout << "### Start request ID:" << david << " host:" << qPrintable(urigoup.host()) << " path:" << qPrintable(urigoup.path()) << std::endl;
  QObject::connect(this, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), this, SLOT(SaveData(const QHttpResponseHeader &)));
}
inline QString GetOPTIONSData() { return davoption; }
inline QStringList GetAllowMethod() { return allowlist; }
inline QString GetDavLevel() { return davlevel; }
protected:
    int david;        /* current process id */
    QUrl urigoup;     /* url path */
    QString davoption;
    QString davlevel;
    QHttpRequestHeader header;
    QStringList allowlist;
private:
signals:
  void LastDone();
  void ErrorNoDAV();
public slots:

void SaveData(const QHttpResponseHeader &responseHeader )
{
    int headercode = responseHeader.statusCode();
    if (headercode !=200) {
       emit ErrorNoDAV();
       abort();
       return;        
    }
    std::cout << "###----------------------------------------------------"  << std::endl;
    std::cout << "### Process ID:\t" << david  << std::endl;
    std::cout << "### Header code:\t" << headercode << std::endl;
    QStringList headerin = responseHeader.keys();
    for (int i = 0; i < headerin.size(); ++i) {
        QString name = headerin.at(i);
        QString value = responseHeader.value(headerin.at(i));
                value = value.replace(" ","");
                name = name.toLower();
                if (name == "dav") {
                  davlevel = value;
                }
                if (name == "allow") {
                allowlist = value.split(",");
                }
        davoption.append(QString("%1|%2\n").arg(name).arg(responseHeader.value(headerin.at(i))));
    }
    
    
    QStringList headeresponser = davoption.split("\n");
   
    fwriteutf8("cache/davoption.dat",davoption);
    
    std::cout << "### Header params--------------------------------------"  << std::endl;
    for (int o = 0; o < headeresponser.size(); ++o) {
    std::cout << "### " << qPrintable(headeresponser.at(o)) << std::endl; 
    }
    std::cout << "###----------------------------------------------------"  << std::endl;
    std::cout << "### Dav level:\t" << qPrintable(davlevel) << std::endl;
    std::cout << "###----------------------------------------------------"  << std::endl;
    for (int i = 0; i < allowlist.size(); ++i) {
    std::cout << "### Allowed method:\t" << "|" << qPrintable(allowlist.at(i)) <<  "|" << std::endl; 
    }
    std::cout << "###----------------------------------------------------"  << std::endl;
    emit LastDone();
    abort();
    if (WORKMAIN == 5) {
    //////QCoreApplication::exit(0);
    }
}

};




class HTTP_propfind : public QHttp
{
    Q_OBJECT
//
public: HTTP_propfind( QUrl urigo , QObject * parent = 0 )
{
 urigoup = QUrl(urigo);
 doneCall =0;
 readyCall =0;
 setHost(urigoup.host(), 80);
 setUser(urigoup.userName(),urigoup.password());
 havingfilelist = true;
 byteArray.clear();
    
         /* xml data to send request list dir */
         QDomDocument davbaseinit;
         QDomProcessingInstruction headerx = davbaseinit.createProcessingInstruction( "xml",QString("version=\"1.0\" encoding=\"utf-8\"" ));
         davbaseinit.appendChild( headerx );
         QDomElement root = davbaseinit.createElement("D:propfind");
         root.setAttribute ("xmlns:D","DAV:");
         QDomElement propname = davbaseinit.createElement("D:allprop");
         root.appendChild(propname);
         davbaseinit.appendChild( root );
    
    
         QDomElement nshost = davbaseinit.createElement("D:namespaces");
         propname.appendChild( nshost );
         QDomElement nsuri = davbaseinit.createElement("D:namespace");
         nsuri.setAttribute ("uri","DAV:");
         nshost.appendChild( nsuri );
    
         /*
         <D:propfind xmlns:D="DAV:">
         <D:allprop>
         <D:namespaces>
         <D:namespace uri="DAV:"/>
         </D:namespaces>
         </D:allprop>
         */
    
         QString question = davbaseinit.toString();
         fwriteutf8("cache/propfinfrequest.xml",question);
         headerleng = question.size();
         byteSendXml.clear();
         byteSendXml.append(question);
         GrepSi("HostDepthUser-AgentAccept-CharsetAccept-LanguageConnectionContent-Type");
         /* xml data to send request list dir */
         header.setRequest("PROPFIND",urigoup.path(),1,1);  /* */
         header.setValue("Host",GrepSi(urigoup.host()));
         header.setValue("Depth",GrepSi("1"));  /* apache2=1  apache coyote=???  other are infinity */
         header.setValue("User-Agent", GrepSi(WEBAGENTNAME));
         header.setValue("Accept-Charset", GrepSi("ISO-8859-1,utf-8;q=0.7,*;q=0.7"));
         header.setValue("Accept-Language", GrepSi("it,de-de;q=0.8,it-it;q=0.6,en-us;q=0.4,en;q=0.2"));
         header.setValue("Connection", GrepSi("keep-alive"));
         header.setValue("Content-Type", GrepSi("text/xml; charset=\"utf-8\"" ));
         header.setContentLength(headerleng);
        std::cout << "header.contentLength()->" << header.contentLength() << std::endl;
}
QString GrepSi( QString m )
{
    headerleng = headerleng + m.size();
    return m;
}
void Start()
{
  david = request(header,byteSendXml,0);
  std::cout << "Start request ID:" << david << " host:" << qPrintable(urigoup.host()) << "|" << qPrintable(urigoup.path()) << std::endl;
  connect(this, SIGNAL(requestFinished(int, bool)), this, SLOT(EndTakeData(int, bool)));
  connect(this, SIGNAL(done(bool)), this, SLOT(abort()));
}
inline QString GetDAVData() { return QString(byteArray.data()); }
protected:
    int david;        /* current process id */
    uint headerleng;
    QUrl urigoup;     /* url path */
    QByteArray byteArray;  /* incomming data */
    QByteArray byteSendXml; /* xml send data */
    int doneCall;
    int readyCall;
    bool havingfilelist;
    QString davoption;
    QHttpRequestHeader header;
private:
signals:
  void LastDone();
  void Launcherror(QString);
public slots:
void EndTakeData( int ei , bool e )
{
   if (e) {
       std::cout <<  qPrintable(errorString()) << std::endl; 
       Launcherror(errorString());
       abort();
       return;
   }
   int headercode = lastResponse().statusCode();
   if (headercode =!207) {
   std::cout <<  qPrintable(errorString()) << std::endl; 
   Launcherror(errorString());
   abort();
   return; 
   }
   
    byteArray.append(readAll());
    
    /////std::cout << "---------------------------------HEADER---------------------------"  << std::endl;
    /////std::cout << "Last http header respond is " << headercode << std::endl;
    QStringList headerin = lastResponse().keys();
    for (int i = 0; i < headerin.size(); ++i) {
    ////std::cout << "" << qPrintable(headerin.at(i)) << " ->" << qPrintable(lastResponse().value(headerin.at(i))) << std::endl; 
    }
    /////std::cout << "---------------------------------HEADER---------------------------"  << std::endl;
    ////std::cout << "---------------------------------DATAIN---------------------------"  << std::endl; 
    ////std::cout <<  qPrintable(QString(byteArray.data())) << std::endl; 
    /////std::cout << "---------------------------------DATAIN---------------------------"  << std::endl;
    emit LastDone();
    
    fwriteutf8("cache/propfinanswer.xml",QString(byteArray.data()));
    
    if (WORKMAIN == 5) {
    ///////QCoreApplication::exit(0);
    }
    
}

};



class DavListDir : public QThread
{
    Q_OBJECT
    
public:
    void run();
    void SetUrl( QUrl u );
signals:
 void statusMessage(QString);
 void TimeEnd();
private:
    QUrl urltogrep;
    HTTP_propfind *jobb;
public slots:
    void PaintData();
};
void DavListDir::SetUrl( QUrl u ) 
{
   urltogrep = QUrl(u); 
   connect(this, SIGNAL(finished()), this, SLOT(PaintData()));
}

void DavListDir::PaintData() 
{
   /* prepare to paint remote dir list on tree model */
   std::cout << "end cycle "  << std::endl;
   std::cout <<  qPrintable(jobb->GetDAVData()) << std::endl; 
}

void DavListDir::run() 
{
    jobb = new HTTP_propfind(urltogrep);
    jobb->Start();
    exec();  
}






/* ############################# class stop ################################################*/


int main(int argc, char* argv[])
{
    //////////Q_INIT_RESOURCE(HTTP_option);
    
  QApplication app(argc, argv);
  std::cout << "Main start Process ID:" << getpid() << std::endl;
    
    if (!NetworkEnable()) {
     std::cout << "Network is not enable or open!" << std::endl;
      return 0;
    }
    
    
    /* method HTTP_propfind HTTP_option  */
    
    DavListDir *cann = new DavListDir();
    cann->SetUrl(QUrl("http://user:pass@192.168.1.33/webdav/www/"));
    cann->start(QThread::HighPriority);
    
    
   
    
    
    
return app.exec();
}


#include "main.moc"







